package com.whut.v_bo;

import com.whut.enums.ProjectSampleItemType;

import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;

public class ProjectSampleV1BO implements Node<ProjectSampleV1BO> {

    private String build;
    private Integer floor;
    private Integer family;
    private ProjectSampleItemType type;
    private List<Check> checks;
    private boolean available;

    private ProjectSampleV1BO parent;
    private List<ProjectSampleV1BO> children;

    public static class Check {
        private Integer id;
        private boolean ok;

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public boolean isOk() {
            return ok;
        }

        public void setOk(boolean ok) {
            this.ok = ok;
        }
    }

    public String getKey() {
        return build + "_" + floor + "_" + family;
    }

    /**
     * 判断楼栋号是否相等
     *
     * @param obj
     * @return
     */
    public boolean buildEquals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        ProjectSampleV1BO other = (ProjectSampleV1BO) obj;

        if (other.getBuild() == null) {
            return false;
        }
        if (build == null) {
            if (other.build != null) {
                return false;
            }
        } else if (!build.equals(other.build)) {
            return false;
        }
        return true;
    }

    public int getLastNum() {
        int num = 0;
        switch (type) {
            case BUILD:

            case FLOOR:
                num = Optional.ofNullable(getChildren())
                        .map(children -> Long.valueOf(children.stream().filter(sample -> sample.isAvailable() && sample.getAvailableSpeed() > 0).count()).intValue())
                        .orElse(0);
                break;
            case FAMILY:
            default:
                // num = 0;
                break;

        }
        return num;
    }

    /**
     * 施工完成速率
     *
     * @return 速率
     */
    public double getSpeed() {
        double speed = 0D;
        switch (type) {
            case BUILD:
                speed = Optional.ofNullable(children)
                        .filter(cs -> !cs.isEmpty())
                        .map(cs -> {
                            double sum = cs.stream().mapToDouble(ProjectSampleV1BO::getSpeed).sum();
                            return BigDecimal.valueOf(sum).divide(BigDecimal.valueOf(cs.size()), 4, BigDecimal.ROUND_DOWN).doubleValue();
                        }).orElse(0D);

                break;
            case FLOOR:
                speed = Optional.ofNullable(checks)
                        .filter(cs -> !cs.isEmpty())
                        .map(cs -> {
                            long okSize = cs.stream().filter(Check::isOk).count();
                            return BigDecimal.valueOf(okSize).divide(BigDecimal.valueOf(cs.size()), 4, BigDecimal.ROUND_DOWN).doubleValue();
                        }).orElse(0D);
                break;
            case FAMILY:
                speed = Optional.ofNullable(parent)
                        .filter(t -> t.getChecks() != null)
                        .filter(t -> !t.getChecks().isEmpty())
                        .map(t -> {
                            long okSize = t.getChecks().stream().filter(Check::isOk).count();
                            return BigDecimal.valueOf(okSize).divide(BigDecimal.valueOf(t.getChecks().size()), 4, BigDecimal.ROUND_DOWN).doubleValue();
                        }).orElse(0D);
                break;
        }
        return speed;
    }

    /**
     * 可以抽样的速率 （可以抽样的check / checks.size）
     *
     * @return 速率
     */
    public double getAvailableSpeed() {
        double speed = 0D;
        switch (type) {
            case BUILD:
                speed = Optional.ofNullable(children)
                        .filter(cs -> !cs.isEmpty())
                        .map(cs -> {
                            double sum = cs.stream().filter(ProjectSampleV1BO::isAvailable).mapToDouble(ProjectSampleV1BO::getAvailableSpeed).sum();
                            return BigDecimal.valueOf(sum).divide(BigDecimal.valueOf(cs.size()), 4, BigDecimal.ROUND_DOWN).doubleValue();
                        }).orElse(0D);

                break;
            case FLOOR:
                speed = Optional.ofNullable(checks)
                        .filter(cs -> !cs.isEmpty())
                        .map(cs -> {
                            long okSize = cs.stream().filter(Check::isOk).count();
                            return BigDecimal.valueOf(okSize).divide(BigDecimal.valueOf(cs.size()), 4, BigDecimal.ROUND_DOWN).doubleValue();
                        }).orElse(0D);
                break;
            case FAMILY:
                speed = Optional.ofNullable(parent)
                        .filter(t -> t.getChecks() != null)
                        .filter(t -> !t.getChecks().isEmpty())
                        .map(t -> {
                            long okSize = t.getChecks().stream().filter(Check::isOk).count();
                            return BigDecimal.valueOf(okSize).divide(BigDecimal.valueOf(t.getChecks().size()), 4, BigDecimal.ROUND_DOWN).doubleValue();
                        }).orElse(0D);
                break;
        }
        return speed;
    }

    public String getBuild() {
        return build != null ? build : (getParent() != null ? getParent().getBuild() : null);
    }

    public void setBuild(String build) {
        this.build = build;
    }

    public Integer getFloor() {
        return floor != null ? floor : (getParent() != null ? getParent().getFloor() : null);
    }

    public void setFloor(Integer floor) {
        this.floor = floor;
    }

    public Integer getFamily() {
        return family != null ? family : (getParent() != null ? getParent().getFamily() : null);
    }

    public void setFamily(Integer family) {
        this.family = family;
    }

    public ProjectSampleItemType getType() {
        return type;
    }

    public void setType(ProjectSampleItemType type) {
        this.type = type;
    }

    public List<Check> getChecks() {
        return checks;
    }

    public void setChecks(List<Check> checks) {
        this.checks = checks;
    }

    public boolean isAvailable() {
        return available;
    }

    public void setAvailable(boolean available) {
        this.available = available;
    }

    @Override
    public ProjectSampleV1BO getParent() {
        return parent;
    }

    public void setParent(ProjectSampleV1BO parent) {
        this.parent = parent;
    }

    @Override
    public List<ProjectSampleV1BO> getChildren() {
        return children;
    }

    public void setChildren(List<ProjectSampleV1BO> children) {
        this.children = children;
    }

}
